昨天不僅完成了 Vuex Module Registration,
也完成了串接 Firebase 登入/登出/自動登入。
今天來建立部落格所有需要的資料庫結構,簡單分為兩個 vuex modules:
tags 這個 module 的內容只有一個 action,
就是 getAllTags,直接來看程式碼:
import { db } from '@/services/fireinit'
import { uniq, flatten } from 'lodash'
export const actions = {
  getAllTags () {
    let postsCol = db.collection('posts').where('isShow', '==', true)
    return postsCol.orderBy('postTime', 'desc').get()
      .then(({ docs }) => {
        let allTags = []
        docs.forEach(doc => {
          allTags.push(doc.data().tags)
        })
        allTags = uniq(flatten(allTags))
        const promises = allTags.map(tag => {
          return postsCol.where('tags', 'array-contains', tag).get()
            .then(({ docs }) => {
              return {
                name: tag,
                size: docs.length,
              }
            })
        })
        return Promise.all(promises)
      })
  }
}
import { db } from '@/services/fireinit'
fireinit 是前天寫好的套件,將 firestore export 為 db,
這樣就可以透過 db 與 firestore 溝通(存、取、修改、刪除)。
import { uniq, flatten } from 'lodash'
從所有的文章中取出 tags, 並且透過 flatten 和 uniq 移除重複的部分。
post 有 7 個 actions:
部落格作者
使用者
由於這個 module 的程式碼較多,這邊就以 action 來分別介紹:
使用 db.collection('posts').add 新增文章,
成功回傳的 data 會自帶 data.id 作為辨別一篇文章的 postId。
而這個 action 會在元件 FormAddPost 被用到。
addPost ({}, payload) {
	return db.collection('posts').add({ ...payload })
		.then(data => ({ id: data.id, ...payload }))
}
修改一篇文章首先需要該篇文章的 postId,
這邊透過 set 並帶入參數 merge: true 自動合併。
而這個 action 會在元件 FormAddPost 被用到。
setPost ({}, payload) {
	return db.collection('posts').doc(payload.postId).set({ ...payload.thePost }, { merge: true })
		.then(() => ({ ...payload.thePost, id: payload.postId }))
}
列出所有文章,並用 orderBy('postTime', 'desc) 按照發布時間排序。
getPostsAdmin () {
	return db.collection('posts').orderBy('postTime', 'desc').get()
		.then(docs => {
			const posts = []
			docs.forEach(doc => {
				posts.push({ ...doc.data(), id: doc.id })
			})
			return posts
		})
}
列出第 payload.pageNum 頁,
且一頁最多 payload.perPage 筆文章,
且使用 where('isShow', '==', true) 只顯示使用者可以看到的文章。
async getPostsByPage ({}, payload) {
	let postsCol = db.collection('posts').where('isShow', '==', true).orderBy('postTime', 'desc')
	let docs = await postsCol.get()
		.then(({ docs }) => docs)
	let startAt = (payload.pageNum - 1) * payload.perPage
	let page = docs[startAt] ? Number(payload.pageNum) : 1
	let size = docs.length
	let pageLength = Math.ceil(size / payload.perPage)
	if (size === 0) return {
		page: 1,
		size: 1,
		posts: []
	}
	let postTime = docs[startAt]
	? docs[startAt].data().postTime
	: docs[0].data().postTime
	return await postsCol.startAt(postTime).limit(payload.perPage).get()
		.then(({ docs }) => {
			const posts = []
			docs.forEach(doc => {
				posts.push({ ...doc.data(), id: doc.id })
			})
			return {
				page,
				pageLength,
				posts
			}
		})
}
透過 where('tags', 'array-contains', tagId) 來篩選出擁有該標籤的所有文章。
getPostsTag ({}, tagId) {
	return db.collection('posts').where('isShow', '==', true).where('tags', 'array-contains', tagId).get()
		.then(docs => {
			const posts = []
			docs.forEach(doc => {
				posts.push({ ...doc.data(), id: doc.id })
			})
			return posts
		})
}
根據 postId 取的該文章內容。
getPostByPostId ({}, postId) {
	return db.collection('posts').doc(postId).get()
		.then(doc => doc.data())
}
取得所有使用者可見的文章列表,並按照發布日期排序。
getPosts () {
	return db.collection('posts').where('isShow', '==', true).orderBy('postTime', 'desc').get()
		.then(({ docs }) => {
			const posts = []
			docs.forEach(doc => {
				posts.push({ ...doc.data(), id: doc.id })
			})
			return posts
		})
}
注意:記得要回 firebase 的 Database 建立索引如下圖:

明天開始利用這些開發好的 actions 切版,
今天就暫時無法 Demo 了。
指令:
git clone -b 023-module-tags-post --single-branch https://github.com/hunterliu1003/blog.git
cd blog
npm install